home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 November: Tool Chest / Dev.CD Nov 94.toast / Sample Code / Newton Sample Code 1.2 / Connection Kit / SyncAnotherOne-2 / Sync Another One.text < prev    next >
Encoding:
Text File  |  1994-03-09  |  18.6 KB  |  504 lines  |  [TEXT/MPS ]

  1. // Copyright © 1993,4 Apple Computer, Inc. All rights reserved
  2.  
  3. // application constants
  4. constant kAppSymbol := '|SoupTDS:PIEDTS| ;
  5. constant kPackageName := "soupTDS:PIEDTS" ;
  6. constant kAppName := "MetaData";
  7.  
  8. // soup constants
  9. constant kAppSoupName := kPackageName ;
  10. constant kSoupIndices := '[] ;
  11. constant kAppObject := '["Thing that doesn't suck", "Things that don't suck"];
  12.  
  13. // metadata constants
  14. constant kMetaDataVersion := 2 ;    // local revision number of our metadata spec
  15.  
  16. // a date format to use
  17. DefConst('kAppDateFormat,
  18.     GetDateStringSpec([[kElementHour, kFOrmatNumeric],
  19.                              [kElementMinute, kFormatNumeric],
  20.                              [kElementAMPM, kFormatAbbr]]));
  21.  
  22. // ---- End Project Data ----
  23.  
  24.  
  25. // ---- File Sync Another One.t ----
  26.  
  27. // Before Script for "MetaDataApp"
  28. // Copyright © 1993,4 Apple Computer, Inc. All rights reserved
  29.  
  30. MetaDataApp :=
  31.    {
  32.     viewSetupDoneScript:
  33.       func()
  34.       begin
  35.          tdsSoup := call kRegisterCardSoupFunc with
  36.                   (kAppSoupName, kSoupIndices, kAppSymbol, kAppObject);
  37.          // tdsCursor := Query(tdsSoup, {type: 'index, indexPath: 'aString});
  38.          tdsCursor := Query(tdsSoup, {type: 'index});
  39.          if NOT tdsCursor:Entry() then
  40.             :FillSoup();
  41.           :InitMetaData();
  42.          theSoupFrame := tdsCursor:Reset();
  43.       end,
  44.     viewQuitScript:
  45.       func()
  46.       begin
  47.           // unregister card soups
  48.          call kUnregisterCardSoupFunc with (kAppSoupName) ;
  49.       
  50.           // cleanup soup and cursor references
  51.           tdsCursor := nil ;
  52.           tdsSoup := nil ;
  53.       
  54.           // cleanup other extraneous references
  55.           theSoupFrame := nil ;
  56.           theTextFrame := nil ;
  57.       end,
  58.     theTextFrame: nil,
  59.     tdsSoup:
  60.       nil
  61.       
  62.       // holds the soup at runtime,
  63.     TestImport:
  64.       func()
  65.       begin
  66.           if theTextFrame then
  67.           begin
  68.              theSoupFrame := MetaData:import(theTextFrame);
  69.              print(theSoupFrame);
  70.           end else
  71.               :Notify(kNotifyAlert, EnsureInternal(kAppName),
  72.                           EnsureInternal("You must first test exporting by pressing the 'Test Export Script' button"));
  73.       end,
  74.     viewBounds: {left: 0, top: 0, right: 240, bottom: 150},
  75.     appObject: kAppObject,
  76.     _proto: protoApp,
  77.     FillSoup:
  78.       func()
  79.       begin
  80.          local i;
  81.          print("Filling Soup");
  82.             for i := 1 to 20 do
  83.                tdsSoup:AddToDefaultStore({
  84.                   aString: GetRandomWord(5,20) & $- & GetRandomWord(5,20),
  85.                   anInteger: Random(0,10000),
  86.                   aReal: Random(0, 10000)/100,
  87.                   aSymbol: MySymbolArray[Random(0, length(MySymbolArray)-1)],
  88.                  aDate: Time(),
  89.                    aTime: Time(),
  90.                   aDateAndTime: Time(),
  91.                   aCharacter: CHR(Random(ORD($A),ORD($Z))),
  92.                   aBoolean: if Random(0, 1) = 1 then TRUE else NIL,
  93.                   aFolder: if Random(0, 2) = 0 then nil /* Unfiled */ else
  94.                            (foreach folder, name in userConfiguration.userFolders
  95.                             collect folder)[
  96.                               Random(0, length(userConfiguration.userFolders)-1)],
  97.                   aFrame: {
  98.                      aStringSlot: GetRandomWord(1,5),
  99.                      anIntegerSlot: Random(0, 100),
  100.                   },
  101.                   anArray: [Random(0, 9), Random(10,19), Random(20,29)],
  102.                });
  103.           if NOT tdsCursor then
  104.              tdsCursor := Query(tdsSoup, {type: 'index});
  105.          theSoupFrame := tdsCursor:Reset();
  106.       end,
  107.     DestroySoup:
  108.       func()
  109.       begin
  110.          local store, myCursor, mySoup, directorySoup;
  111.       
  112.           // unregister soups with system
  113.           call kUnRegisterCardSoupFunc with (kAppSoupName);
  114.       
  115.       
  116.          // remove the soup from each store currently installed
  117.          foreach store in GetStores() do
  118.             if mySoup := store:GetSoup(kAppSoupName) then
  119.                mySoup:RemoveFromStore();
  120.       
  121.          // remove the soup MetaData
  122.          directorySoup := GetStores()[0]:GetSoup("Directory");
  123.          if directorySoup then
  124.          begin
  125.             myCursor := Query(directorySoup, {type:'index, indexPath:'soup,
  126.                               startKey: kAppSoupName,
  127.                               endTest: func(entry) NOT(StrEqual(entry.soup, kAppSoupName))});
  128.             while myCursor:Entry() do
  129.             begin
  130.                EntryRemoveFromSoup(myCursor:Entry());
  131.                myCursor:Next();
  132.             end;
  133.          end;
  134.           
  135.           // nil out the references to the soup and cursors
  136.           tdsSoup := nil ;
  137.           tdsCursor := nil ;
  138.           theSoupFrame := nil;
  139.       end,
  140.     theSoupFrame: nil,
  141.     appSymbol: kAppSymbol,
  142.     title: "Meta Data Sample",
  143.     MetaData:
  144.       {
  145.       // name of soup within Newton
  146.       soup: kAppSoupName,
  147.       
  148.       // alternate name to show the user
  149.       name: "Meta Data Sample Soup",
  150.       
  151.       // version number, default 1
  152.       version: kMetaDataVersion,
  153.       
  154.       // default frame for a new entry
  155.       newEntry: {
  156.          aString: "default",
  157.          anInteger: 0,
  158.          aReal: 0.0,
  159.          aSymbol: nil,
  160.          aDate: nil,         // check out the export script (heh)
  161.          aTime: nil,         // check out the export script (heh)
  162.          aDateAndTime: nil,  // check out the export script (heh)
  163.          aCharacter: $?,
  164.          aBoolean: NIL,
  165.          aFolder: NIL,
  166.          aFrame: {
  167.             aStringSlot: "default",
  168.             anIntegerSlot: 0,
  169.          },
  170.          anArray: Array(3, 0),
  171.       },
  172.       
  173.       // displayInfo/editInfo/exportInfo entries can have the folowing slots:
  174.       //   slot:      symbol that refers to slot in soup entry being described
  175.       //   type:      type of editor for slot, default 'string
  176.       //      'string, 'char, 'text, 'integer, 'picklist, 'folder, 'e_line
  177.       //      'date, 'time, 'real, 'phone (last 4 not fully implemented)
  178.       //   choices:   in editInfo, array of strings for popups ('picklist)
  179.       //   size:      number of '0' characters that should fit, default 15
  180.       //   hidden:    if true, column will initially be hidden
  181.       //   label:     string for label on Mac/PC, default is slot name
  182.       //   sameLine:  for editInfo only, if true will put on same line as previous
  183.       //   unsearchable: for displayInfo, if true will not allow searches on this field
  184.       //   path:      specifies path to data for search comparisons, defaults to slot
  185.       //   compareScript: symbol for which compare script to use.
  186.       // These are reserved for future use, not implemented now
  187.       //   justify:   'right, 'left, 'center, or 'system
  188.       //   maxChars:   upper limit for input in editInfo
  189.       //   minChars:   lower limit for input in editInfo
  190.       //   maxValue:   max for numeric fields in editInfo
  191.       //   minValue:   min for numeric fields in editInfo
  192.       //   validChar:  script (in meta data) that will be called for
  193.       //               each character in editInfo to validate it.
  194.       //   validField: script (in meta data) that will be called when
  195.       //               the user finishes the field.
  196.       //   numLines:   specifies the number of lines for editInfo
  197.       
  198.       // used in overview list on Mac/PC, order in array controls Mac/PC
  199.       displayInfo: ['aString, 'anInteger, 'aReal, 'aSymbol, 'aDate, 'aTime,
  200.                     'aDateAndTime, 'aCharacter, 'aBoolean, 'aFolder,],
  201.       //              'aFrame1, 'aFrame2, 'anArray1, 'anArray2, 'anArray3],
  202.       
  203.       // used in item list on Mac/PC
  204.       editInfo: ['aString, 'anInteger, 'aReal, 'aSymbol, 'e_line, 'aDate, 'aTime,
  205.                  'aDateAndTime, 'e_line, 'aCharacter, 'aBoolean, 'aFolder, 'e_line,
  206.                  'aFrame1, 'aFrame2, 'anArray1, 'anArray2, 'anArray3],
  207.       
  208.       // used for import/export on Mac/PC
  209.       exportInfo: ['aString, 'anInteger, 'aReal, 'aSymbol, 'aDate, 'aTime,
  210.                    'aDateAndTime, 'aCharacter, 'aBoolean, 'aFolder,
  211.                    'aFrame1, 'aFrame2, 'anArray1, 'anArray2, 'anArray3],
  212.       
  213.       // specifies defaults in displayInfo, editInfo, exportInfo
  214.       defaultDefinitions: {
  215.          aString: {slot: 'aString, size: 41, },
  216.          anInteger: {slot: 'anInteger, type: 'integer, },
  217.          aReal: {slot: 'aReal, type: 'real, },
  218.          aSymbol: {slot: 'aSymbol, type: 'mySymbolType, size: 12, },
  219.          aDate: {slot: 'aDate, type: 'date, },
  220.          aTime: {slot: 'aTime, type: 'time, sameline: TRUE, },
  221.          aDateAndTime: {slot: 'aDateAndTime, type: 'myDateAndTime, },
  222.          aCharacter: {slot: 'aCharacter, type: 'char, },
  223.          aBoolean: {slot: 'aBoolean, type: 'picklist, label: "Boolean", choices: ["TRUE", "FALSE"], },
  224.          aFolder: {slot: 'aFolder, type: 'folder, },
  225.          aFrame1: {slot: 'aFrame.aStringSlot, hidden: TRUE, size: 11, },
  226.          aFrame2: {slot: 'aFrame.anIntegerSlot, type: 'integer, hidden: TRUE, },
  227.          anArray1: {slot: [pathExpr: 'anArray, 0], type: 'integer, hidden: TRUE, },
  228.          anArray2: {slot: [pathExpr: 'anArray, 1], type: 'integer, hidden: TRUE, },
  229.          anArray3: {slot: [pathExpr: 'anArray, 2], type: 'integer, hidden: TRUE, },
  230.       },
  231.       
  232.       // used to lookup values of type slots
  233.       // must be one of:
  234.       //      'string, 'char, 'text, 'integer, 'picklist, 'folder, 'e_line
  235.       //      'date, 'time, 'real, 'phone (last 4 not fully implemented)
  236.       editTypes: {
  237.          mySymbolType: {type: 'picklist, label: "Symbol", choices: ["first", "second", "third", ], },
  238.       },
  239.       
  240.       // text frames have same slots as soup frames, but value
  241.       // for each slot is a string.  The textFrame should also have a slot called
  242.       // originalFrame, which should point to the soup frame (just a convention)
  243.       // Note that the text frame passed to the import script will NOT be the same
  244.       // frame returned from the export script.  (Any slots not mentioned in editInfo
  245.       // won't appear in the frame passed to the import script.)
  246.       
  247.       export: func(theSoupFrame)
  248.       begin
  249.          local theTextFrame := {
  250.             // originalFrame: theSoupFrame,
  251.             aString: theSoupFrame.aString,
  252.             anInteger: SPrintObject(theSoupFrame.anInteger),
  253.             aReal: SPrintObject(theSoupFrame.aReal),
  254.             aSymbol: :MySymbolToString(theSoupFrame.aSymbol),
  255.             aDate: ShortDateStr(if NOT theSoupFrame.aDate then Time() else theSoupFrame.aDate, kIncludeAllElements),
  256.             aTime: TimeStr(if NOT theSoupFrame.aTime then Time() else theSoupFrame.aTime,kAppDateFormat),
  257.             aDateAndTime: ShortDateStr(if NOT theSoupFrame.aDate then Time() else theSoupFrame.aDate, kIncludeAllElements)
  258.                           && TimeStr(if NOT theSoupFrame.aTime then Time() else theSoupFrame.aTime, kAppDateFormat),
  259.             aCharacter: SPrintObject(theSoupFrame.aCharacter),
  260.             aBoolean: defaultDefinitions.aBoolean.choices[if theSoupFrame.aBoolean then 0 else 1],
  261.             aFolder: if theSoupFrame.aFolder then SPrintObject(theSoupFrame.aFolder),
  262.             aFrame1: theSoupFrame.aFrame.aStringSlot,
  263.             aFrame2: SPrintObject(theSoupFrame.aFrame.anIntegerSlot),
  264.             anArray1: SPrintObject(theSoupFrame.anArray[0]),
  265.             anArray2: SPrintObject(theSoupFrame.anArray[1]),
  266.             anArray3: SPrintObject(theSoupFrame.anArray[2]),
  267.          };
  268.          return theTextFrame
  269.       end,
  270.       
  271.       // convert a text frame to a soup entry frame
  272.       import: func(theTextFrame)
  273.       begin
  274.          local n := StringToNumber(theTextFrame.anInteger);
  275.          local m := StringToNumber(theTextFrame.aFrame2);
  276.          local o := [
  277.             StringToNumber(theTextFrame.anArray1),
  278.             StringToNumber(theTextFrame.anArray2),
  279.             StringToNumber(theTextFrame.anArray3),
  280.          ];
  281.          local theSoupFrame := {
  282.             aString: theTextFrame.aString,
  283.             anInteger: if n = abs(n) then floor(n) else ceiling(n),
  284.             aReal: StringToNumber(theTextFrame.aReal),
  285.             aSymbol: :StringToMySymbol(theTextFrame.aSymbol),
  286.             aDate: StringToDate(theTextFrame.aDate),
  287.             aTime: :GetTime(theTextFrame.atime),
  288.             aDateAndTime: StringToDate(theTextFrame.aDateAndTime),
  289.             aCharacter: if length(theTextFrame.aCharacter) > 0 then theTextFrame.aCharacter[0] else $ ,
  290.             aBoolean: StrCompare(theTextFrame.aBoolean, defaultDefinitions.aBoolean.choices[0]) = 0,
  291.             aFolder: if theTextFrame.aFolder then :GetSymbol(theTextFrame.aFolder),
  292.             aFrame: {
  293.                aStringSlot: theTextFrame.aFrame1,
  294.                anIntegerSlot: if m = abs(m) then floor(m) else ceiling(m),
  295.             },
  296.             anArray: [
  297.                if o[0] = abs(o[0]) then floor(o[0]) else ceiling(o[0]),
  298.                if o[1] = abs(o[1]) then floor(o[1]) else ceiling(o[1]),
  299.                if o[2] = abs(o[2]) then floor(o[2]) else ceiling(o[2]),
  300.             ],
  301.          };
  302.          return theSoupFrame;
  303.       end,
  304.       
  305.       // these supporting functions are used by import/export to
  306.       // convert strings to symbols and vice-versa.  They're accessible
  307.       // because the context for the import and export scripts is a copy
  308.       // of the meta data frame itself.
  309.       MySymbolToString: func(theSymbol)
  310.          editTypes.mySymbolType.choices[
  311.             if NOT theSymbol or theSymbol = 'firstSymbol then 0
  312.             else if theSymbol = 'secondSymbol then 1
  313.             else if theSymbol = 'thirdSymbol then 2
  314.          ],
  315.       
  316.       StringToMySymbol: func(theString)
  317.          if StrCompare(theString, editTypes.mySymbolType.choices[0]) = 0 then 'firstSymbol
  318.          else if StrCompare(theString, editTypes.mySymbolType.choices[1]) = 0 then 'secondSymbol
  319.          else if StrCompare(theString, editTypes.mySymbolType.choices[2]) = 0 then 'thirdSymbol
  320.          else 'firstSymbol, 
  321.       
  322.       // need to put a wrapper around the functions that could make a symbol
  323.       // 1.0 uses MakeSymbol, 2.0 uses Intern
  324.       GetSymbol: func(string)
  325.           if functions.Intern then
  326.               Intern(string)
  327.           else
  328.               MakeSymbol(String),
  329.       
  330.       // yet another function to account for differences between 1.0 and 2.0
  331.       // in 1.0, StringToTime is broken, so you have to use StringToDate,
  332.       // but this will add todays date to the time.
  333.       GetTime: func(string)
  334.           if ClassOf(StringToTime("11:00 am")) = 'frame then
  335.               StringToDate(string)
  336.           else
  337.               StringToTime(string),
  338.       
  339.       
  340.       // used to write custom comparisons for fields.
  341.       // Slots are references by compareScript slots in displayInfo array.
  342.       // description contains:
  343.       //   slotname:   path to data within the current frame
  344.       //   datatype:   value of 'type slot in frame
  345.       //   searchtype: search requested by user (0-9)
  346.       //   searchtext: what the user typed in
  347.       //   searchvalue: use to store converted values from searchtext
  348.       RealCompare: func(entry, description)
  349.          begin
  350.             TRUE;
  351.          end,
  352.       
  353.       compareScripts: {
  354.          aRealCompare: func (entry, description) :RealCompare(entry, description),
  355.          aSymbolCompare: func (entry, description) TRUE,
  356.       },
  357.       },
  358.     tdsCursor: nil,
  359.     TestExport:
  360.       func()
  361.       begin
  362.           if theSoupFrame then
  363.           begin
  364.              theTextFrame := MetaData:export(theSoupFrame);
  365.              print(theTextFrame);
  366.           end else
  367.               :Notify(kNotifyAlert, EnsureInternal(kAppName),
  368.                       EnsureInternal("There is no soup, create one by pressing the 'Rebuild the Soup!' button"));
  369.       end,
  370.     MySymbolArray:
  371.       [
  372.       'firstSymbol,
  373.       'secondSymbol,
  374.       'thirdSymbol,
  375.       ],
  376.     TestNewEntry:
  377.       func()
  378.       begin
  379.           if tdsSoup then
  380.           begin
  381.               theSoupFrame := DeepClone(MetaData.newEntry);
  382.               tdsSoup:Add(theSoupFrame);
  383.               theTextFrame := MetaData:export(theSoupFrame);
  384.               print(theTextFrame);
  385.           end else
  386.               :Notify(kNotifyAlert, EnsureInternal(kAppName),
  387.                           EnsureInternal("There is no soup to add to. Rebuild using the 'Rebuild the Soup!' button"));
  388.       end,
  389.     debug: "MetaDataApp",
  390.     InitMetaData:
  391.       func()
  392.       begin
  393.          // remove any old soup MetaData then add the latest
  394.           local addEntry := nil ;
  395.          local directorySoup := GetStores()[0]:GetSoup("Directory");
  396.          if directorySoup then
  397.          begin
  398.               // get a the metaData soup entry
  399.             myCursor := Query(directorySoup, {type:'index, indexPath:'soup,
  400.                               startKey: kAppSoupName,
  401.                               endTest: func(entry) NOT(StrEqual(entry.soup, kAppSoupName))});
  402.       
  403.               // if the metaData spec is not the latest version
  404.               // for the app, remove it
  405.               if myCursor:Entry() AND (myCursor:Entry().version < kMetaDataVersion) then
  406.               begin
  407.                   EntryRemoveFromSoup(myCursor:Entry());
  408.                   addEntry := true ;
  409.                   // if this happens, could be other stuff to remove
  410.                   while myCursor:Next() do
  411.                       EntryRemoveFromSoup(myCursor:Entry());
  412.               end;
  413.       
  414.               // if needed, add a metaData entry
  415.               if addEntry then
  416.                    directorySoup:Add(Clone(MetaData));
  417.          end;
  418.       end
  419.    };
  420.  
  421. testExportButton := /* child of MetaDataApp */
  422.    {text: "Test Export Script",
  423.     buttonClickScript:
  424.       func()
  425.       begin
  426.          :Parent():TestExport();
  427.       end,
  428.     viewBounds: {left: 28, top: 20, right: 212, bottom: 36},
  429.     _proto: protoTextButton,
  430.     debug: "testExportButton"
  431.    };
  432.  
  433.  
  434.  
  435. testImportButton := /* child of MetaDataApp */
  436.    {text: "Test Import Script",
  437.     buttonClickScript:
  438.       func()
  439.       begin
  440.          :Parent():TestImport();
  441.       end,
  442.     viewBounds: {left: 28, top: 44, right: 212, bottom: 60},
  443.     _proto: protoTextButton,
  444.     debug: "testImportButton"
  445.    };
  446.  
  447.  
  448.  
  449. testNewButton := /* child of MetaDataApp */
  450.    {text: "Test New Entry",
  451.     buttonClickScript:
  452.       func()
  453.       begin
  454.          :Parent():TestNewEntry();
  455.       end,
  456.     viewBounds: {left: 28, top: 68, right: 212, bottom: 84},
  457.     _proto: protoTextButton,
  458.     debug: "testNewButton"
  459.    };
  460.  
  461.  
  462.  
  463. rebuildSoup := /* child of MetaDataApp */
  464.    {text: "Rebuild the Soup!",
  465.     buttonClickScript:
  466.       func()
  467.       begin
  468.          foreach store in GetStores() do begin
  469.             if soup := store:GetSoup(kAppSoupName) then
  470.                soup:RemoveAllEntries();
  471.           end;
  472.           if not tdsSoup then
  473.               tdsSoup := call kRegisterCardSoupFunc with
  474.                   (kAppSoupName, kSoupIndices, kAppSymbol, kAppObject);
  475.          :FillSoup();
  476.       end,
  477.     viewBounds: {left: 28, top: 92, right: 210, bottom: 106},
  478.     _proto: protoTextButton,
  479.     debug: "rebuildSoup"
  480.    };
  481.  
  482.  
  483.  
  484. zapSoup := /* child of MetaDataApp */
  485.    {text: "Delete the Soup!",
  486.     buttonClickScript:
  487.       func()
  488.       begin
  489.          :DestroySoup();
  490.       end,
  491.     viewBounds: {left: 28, top: 116, right: 210, bottom: 130},
  492.     _proto: protoTextButton,
  493.     debug: "zapSoup"
  494.    };
  495.  
  496.  
  497.  
  498.  
  499.  
  500.  
  501.  
  502. // ---- Beginning of section for non used Layout files ----
  503.  
  504. // End of output